package com.vueapi.config;

import com.vueapi.domain.HjExceptionLog;
import com.vueapi.exception.BlogException;
import com.vueapi.exception.TokenException;
import com.vueapi.exception.UserException;
import com.vueapi.service.HjExceptionLogService;
import com.vueapi.utils.HttpContextUtil;
import com.vueapi.utils.IPUtils;
import com.vueapi.utils.ResultUtils;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.ip2region.core.Ip2regionSearcher;
import net.dreamlu.mica.ip2region.core.IpInfo;
import org.apache.ibatis.reflection.ExceptionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.SQLException;

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @Autowired
    private HjExceptionLogService exceptionLogService;

    @Autowired
    private Ip2regionSearcher ip2regionSearcher;

    //特定异常
    @ExceptionHandler(ArithmeticException.class)
    public ResultUtils arithmeticException(ArithmeticException e) {
        saveException(e,e.getMessage());
        log.error("捕获到了特定异常:({})....",e.getMessage());
        return ResultUtils.fail("执行了ArithmeticException异常处理..");
    }

    //自定义异常
    @ExceptionHandler(TokenException.class)
    public ResultUtils tokenException(TokenException e) {
        saveException(e, e.getErrMsg());
        log.error("捕获到了特定异常:({})....",e.getErrMsg());
        return ResultUtils.fail(e.getCode(),e.getMessage(),"");
    }

    //自定义异常
    @ExceptionHandler(UserException.class)
    public ResultUtils userException(UserException e) {
        saveException(e, e.getErrMsg());
        log.error("捕获到了特定异常:({})....",e.getErrMsg());
        return ResultUtils.fail(e.getCode(),e.getErrMsg(),"");
    }

    //自定义异常
    @ExceptionHandler(BlogException.class)
    public ResultUtils blogException(BlogException e) {
        saveException(e, e.getErrMsg());
        log.error("捕获到了特定异常:({})....",e.getErrMsg());
        return ResultUtils.fail(e.getCode(),e.getErrMsg(),"");
    }

    @ExceptionHandler(SQLException.class)
    public ResultUtils sqlException(SQLException e) {
        saveException(e,"SQL异常，具体查看服务器日志");
        log.error("捕获到了SQL异常:({})....",e.getMessage());
        return ResultUtils.fail(500,"服务器错误，请联系管理员","");
    }

    //指定出现什么异常执行这个方法
    @ExceptionHandler(Exception.class)
    public ResultUtils exception(Exception e) {
        saveException(e,e.getMessage());
        log.error("捕获到了服务器异常:({})....",e.getMessage());
        return ResultUtils.fail(500,"服务器错误，请联系管理员","");
    }

    //  将错误信息入库
    private void saveException(Exception e,String message) {
        // 获取异常发生的操作IP
        String ip = IPUtils.getIpAddr(HttpContextUtil.getHttpServletRequest());
        IpInfo ipInfo = ip2regionSearcher.memorySearch(ip);
        String address = "UNKNOWN";
        if(ipInfo != null){
            address = ipInfo.getAddress();
        }

        // 获取错误堆栈
        String stackTrace = getExceptionStringStackTrace(e);

        // 将错误日志入库
        HjExceptionLog exceptionLog = new HjExceptionLog();
        exceptionLog.setMessage(message);
        exceptionLog.setIp(ip);
        exceptionLog.setIpSource(address);
//        exceptionLog.setParams(stackTrace);
        exceptionLogService.save(exceptionLog);
    }

    public static String getExceptionStringStackTrace(Exception e) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        return sw.toString();
    }


}
